/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package swym.protocol.server;

import swym.protocol.*;
import swym.server.*;
import swym.server.config.*;
import java.net.*;
import java.io.*;

/**
 *
 * @author mschaefer
 */
public class MessageHandler 
{
    protected final String userName;
    protected final String clientName;
    protected final int requestID;
    protected final String type;
    
    protected User   user;
    protected Client client;
    
    protected final boolean isDebugMode;
    
    private MessageHandler() 
    {
        userName = null;
        clientName = null;
        requestID = -1;
        type = "";
        
        isDebugMode = Settings.isDebugMode();
    }
    
    public static MessageHandler parseMessage( ActionMessage message, ClientSocket socket )
            throws MessageException, IOException
    {
        MessageHandler handler = null;
        
        try
        {
            if ( message.getType().equals( ActionMessage.TYPE_REGISTER ) )
                handler = new RegisterMessageHandler( message );
            
            else if ( message.getType().equals( ActionMessage.TYPE_FILE ) )
                handler = new FileMessageHandler( message );
            
            else if ( message.getType().equals( ActionMessage.TYPE_CLOSE ) )
                handler = new CloseMessageHandler( message );
            
            else if ( message.getType().equals( ActionMessage.TYPE_LOGIN ))
                handler = new LoginMessageHandler( message );
            
            else if ( message.getType().equals( ActionMessage.TYPE_CLIENT_QUERY))
                handler = new ConnectedClientsQueryMessageHandler(message);
            
            else if ( message.getType().equals( ActionMessage.TYPE_UPDATE))
                handler = new UpdateMessageHandler(message);
            
            else
                throw new InvalidMessageException( message.getRequestID(),
                                                   "invalid message type: " + message.getType() );
        }
        catch ( MessageException e )
        {
            ConfirmActionMessage confirmation = new ConfirmActionMessage( message.getUserName(), 
                                                                          message.getClientName(), 
                                                                          e.getRequestID() );
            confirmation.setErrorMessage( e.getMessage() );
            confirmation.setReturnCode( e.getReturnCode() );
            
            writeMessage( socket, confirmation );
            
            throw e;
        }
        
        return handler;
    }
    
    /**
     * This method implements a table which allows the correct action
     * handler to handle the incoming message.
     * @param message
     * @param socket
     */
    public static void handleMessage( MessageHandler handler, ClientSocket socket ) 
            throws MessageException, IOException, CloseConnectionException
    {
        try
        {
            Log.writeEntry( "handling message: " + handler.toString() );
            
            handler.handleMessage( socket) ;       
        }
        catch ( MessageException e )
        {
            ConfirmActionMessage confirmation = new ConfirmActionMessage( handler.getUserName(), 
                                                                          handler.getClientName(), 
                                                                          e.getRequestID() );
            confirmation.setErrorMessage( e.getMessage() );
            confirmation.setReturnCode( e.getReturnCode() );
            
            writeMessage( socket, confirmation );
            
            throw e;
        }
    }
    
    protected MessageHandler( ActionMessage message, boolean ignoreUnregisteredClient )
            throws MessageException
    {
        userName = message.getUserName();
        clientName = message.getClientName();
        requestID = message.getRequestID();
        type = message.getType();
        
        isDebugMode = Settings.isDebugMode();
        
        user   = null;
        client = null;
        
        // Try to create user and client objects, if they are already registered.
        user = UserManager.getInstance().getUser( message.getUserName() );
        
        if ( user != null )
            client = user.getClient( message.getClientName() );  
        
        if ( !ignoreUnregisteredClient && ( user == null || client == null ) )
            throw new UnregisteredClientException( requestID, "user or client unregistered" );
    }
    
    protected MessageHandler( ActionMessage message )
            throws UnregisteredClientException
    {
        userName = message.getUserName();
        clientName = message.getClientName();
        requestID = message.getRequestID();
        type = message.getType();
        
        isDebugMode = Settings.isDebugMode();
        
        user   = null;
        client = null;
        
        // Try to create user and client objects, if they are already registered.
        user = UserManager.getInstance().getUser( message.getUserName() );
        
        if ( user != null )
            client = user.getClient( message.getClientName() );   
        
        if ( user == null || client == null )
            throw new UnregisteredClientException( requestID, "user or client unregistered" );
    }
    
    protected void handleMessage( ClientSocket socket ) 
        throws IOException, MessageException, CloseConnectionException
    { throw new RuntimeException( "handleMessage not overrided: " + this.toString() ); }
    
    
    public String getUserName()
    {
        return userName;
    }
    
    public String getClientName()
    {
        return clientName;
    }
    
    public int getRequestID()
    {
        return requestID;
    }
    
    // This may be null if not already registered.
    public User getUser()
    {
        return user;
    }
    
    // This may be null if not already registered.
    public Client getClient()
    {
        return client;
    }
    
    public String toString()
    {
        return "message handler: " + type + " req ID: " + requestID;
    }
    
    /**
     * Writes a message object to the socket.
     * 
     * @param socket
     * @param message
     * @throws java.io.IOException
     */
    protected static void writeMessage( ClientSocket socket, ActionMessage message ) throws IOException
    {
        Log.writeEntry( "writing message: " + message.toString() );
        ObjectOutputStream out = socket.getOutputStream();
        
        out.writeObject( message );
        out.flush();
    }
    
    protected static Object readMessage( ClientSocket socket ) throws IOException, ClassNotFoundException 
    {
        return socket.getInputStream().readObject();
    }
}
